home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / drivers.arc / SLIP8250.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-10-20  |  14.7 KB  |  619 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm    ;SEE ENCLOSED COPYRIGHT MESSAGE
  4.  
  5. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  6. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  7.  
  8. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec
  9. ;*  Portions (C) Copyright 1988 Phil Karn
  10. ;*
  11. ;*  Permission is granted to any individual or institution to use, copy,
  12. ;*  modify, or redistribute this software and its documentation provided
  13. ;*  this notice and the copyright notices are retained.  This software may
  14. ;*  not be distributed for profit, either in original form or in derivative
  15. ;*  works.  Phil Karn makes no representations about the suitability
  16. ;*  of this software for any purpose.  PHIL KARN GIVES NO WARRANTY,
  17. ;*  EITHER EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION
  18. ;*  PROVIDED, INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY
  19. ;*  AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  20. ;*/
  21.  
  22. code    segment    byte public
  23.     assume    cs:code, ds:code
  24.  
  25. ;8250 definitions
  26. ;Control/status register offsets from base address
  27. THR    equ    0        ;Transmitter holding register
  28. RBR    equ    0        ;Receiver buffer register
  29. DLL    equ    0        ;Divisor latch LSB
  30. DLM    equ    1        ;Divisor latch MSB
  31. IER    equ    1        ;Interrupt enable register
  32. IIR    equ    2        ;Interrupt ident register
  33. FCR    equ    2        ;16550 FIFO control register
  34. LCR    equ    3        ;Line control register
  35. MCR    equ    4        ;Modem control register
  36. LSR    equ    5        ;Line status register
  37. MSR    equ    6        ;Modem status register
  38.  
  39. ;8250 Line Control Register
  40. LCR_5BITS    equ    0    ;5 bit words
  41. LCR_6BITS    equ    1    ;6 bit words
  42. LCR_7BITS    equ    2    ;7 bit words
  43. LCR_8BITS    equ    3    ;8 bit words
  44. LCR_NSB        equ    4    ;Number of stop bits
  45. LCR_PEN        equ    8    ;Parity enable
  46. LCR_EPS        equ    10h    ;Even parity select
  47. LCR_SP        equ    20h    ;Stick parity
  48. LCR_SB        equ    40h    ;Set break
  49. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  50.  
  51. ;16550 Line Control Register
  52. FCR_RCVR    equ    002h    ;Reset Receive FIFO
  53. FCR_XMIT    equ    004h    ;Reset Transmit FIFO
  54. FCR_1        equ    001h    ;One byte FIFO
  55. FCR_4        equ    041h    ;Four byte FIFO
  56. FCR_8        equ    081h    ;Eight byte FIFO
  57. FCR_14        equ    0c1h    ;Fourteen byte FIFO
  58.  
  59. ;8250 Line Status Register
  60. LSR_DR    equ    1    ;Data ready
  61. LSR_OE    equ    2    ;Overrun error
  62. LSR_PE    equ    4    ;Parity error
  63. LSR_FE    equ    8    ;Framing error
  64. LSR_BI    equ    10h    ;Break interrupt
  65. LSR_THRE equ    20h    ;Transmitter line holding register empty
  66. LSR_TSRE equ    40h    ;Transmitter shift register empty
  67.  
  68. ;8250 Interrupt Identification Register
  69. IIR_IP        equ    1    ;0 if interrupt pending
  70. IIR_ID        equ    6    ;Mask for interrupt ID
  71. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  72. IIR_RDA        equ    4    ;Receiver data available interrupt
  73. IIR_THRE    equ    2    ;Transmitter holding register empty int
  74. IIR_MSTAT    equ    0    ;Modem status interrupt
  75.  
  76. ;8250 interrupt enable register bits
  77. IER_DAV    equ    1    ;Data available interrupt
  78. IER_TxE    equ    2    ;Tx buffer empty interrupt
  79. IER_RLS    equ    4    ;Receive line status interrupt
  80. IER_MS    equ    8    ;Modem status interrupt
  81.  
  82. ;8250 Modem control register
  83. MCR_DTR    equ    1    ;Data Terminal Ready
  84. MCR_RTS    equ    2    ;Request to Send
  85. MCR_OUT1 equ    4    ;Out 1 (not used)
  86. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  87. MCR_LOOP equ    10h    ;Loopback test mode
  88.  
  89. ;8250 Modem Status Register
  90. MSR_DCTS equ    1    ;Delta Clear-to-Send
  91. MSR_DDSR equ    2    ;Delta Data Set Ready
  92. MSR_TERI equ    4    ;Trailing edge ring indicator
  93. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  94. MSR_CTS    equ    10h    ;Clear to send
  95. MSR_DSR equ    20h    ;Data set ready
  96. MSR_RI    equ    40h    ;Ring indicator
  97. MSR_RLSD equ    80h    ;Received line signal detect
  98.  
  99. ;Slip Definitions
  100. FR_END        equ    0c0h        ;Frame End
  101. FR_ESC        equ    0dbh        ;Frame Escape
  102. T_FR_END    equ    0dch        ;Transposed frame end
  103. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  104.  
  105.     public    int_no
  106. int_no        db    3,0,0,0        ; interrupt number.
  107. io_addr        dw    03f8h,0        ; I/O address for COM1.
  108. baud_rate    dw    0,0        ; We support baud rates higher than 65535.
  109. baudclk        label    word
  110.         dd    115200        ;1.8432 Mhz / 16
  111.  
  112.     public    driver_class, driver_type, driver_name
  113. driver_class    db    6        ;from the packet spec
  114. driver_type    db    0        ;from the packet spec
  115. driver_name    db    'SLIP8250',0    ;name of the driver.
  116.  
  117.  
  118. recv_buf_size    dw    3000        ;receive buffer size
  119. recv_buf    dw    ?        ;->receive buffer
  120. recv_buf_end    dw    ?        ;->after end of buffer
  121. recv_buf_head    dw    ?        ;->next character to get
  122. recv_buf_tail    dw    ?        ;->next character to store
  123. recv_cnt    dw    ?        ;number of characters in the queue.
  124.  
  125. send_buf_size    dw    3000        ;send buffer size
  126. send_buf    dw    ?        ;->send buffer
  127. send_buf_end    dw    ?        ;->after end of buffer
  128. send_buf_head    dw    ?        ;->next character to get
  129. send_buf_tail    dw    ?        ;->next character to store
  130. send_cnt    dw    ?        ;number of characters in the queue.
  131.  
  132.  
  133.     public    send_pkt
  134. send_pkt:
  135. ;enter with ds:si -> packet, cx = packet length.
  136. ;exit with nc if ok, or else cy if error, dh set to error number.
  137.     assume    ds:nothing
  138.  
  139.     push    cs
  140.     pop    es
  141.     mov    di,send_buf_tail
  142.     mov    bx,send_cnt
  143.  
  144.     mov    al,FR_END        ;Flush out any line garbage
  145.     call    send_char
  146.  
  147. ;Copy input to output, escaping special characters
  148. send_pkt_1:
  149.     lodsb
  150.     cmp    al,FR_ESC        ;escape FR_ESC with FR_ESC and T_FR_ESC
  151.     jne    send_pkt_2
  152.     mov    al,FR_ESC
  153.     call    send_char
  154.     mov    al,T_FR_ESC
  155.     jmp    short send_pkt_3
  156. send_pkt_2:
  157.     cmp    al,FR_END        ;escape FR_END with FR_ESC and T_FR_END
  158.     jne    send_pkt_3
  159.     mov    al,FR_ESC
  160.     call    send_char
  161.     mov    al,T_FR_END
  162. send_pkt_3:
  163.     call    send_char
  164.     loop    send_pkt_1
  165.     mov    al,FR_END        ;terminate it with a FR_END
  166.     call    send_char
  167.     mov    send_buf_tail,di
  168.     mov    send_cnt,bx
  169.  
  170. ;Enable transmitter buffer empty interrupt.
  171.  
  172.     mov    ah,IER_TxE
  173.     loadport
  174.     setport    IER
  175.     call    setbit
  176.     ret
  177.  
  178.  
  179. send_char:
  180. ;stuff the character in al into the transmit buffer, but only if there
  181. ;is enough room, otherwise ignore the char.
  182.     assume    ds:nothing
  183.     mov    dx,send_cnt        ;too many chars?
  184.     cmp    dx,send_buf_size
  185.     je    send_char_1        ;yes.
  186.     inc    bx            ;count up a char.
  187.     stosb                ;store the char.
  188.     cmp    di,send_buf_end        ;do we need to wrap around?
  189.     jne    send_char_1        ;no.
  190.     mov    di,send_buf        ;yes - reload with beginning.
  191. send_char_1:
  192.     ret
  193.  
  194.  
  195.     public    get_address
  196. get_address:
  197. ;get the address of the interface.
  198. ;enter with es:di -> place to get the address, cx = size of address buffer.
  199. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  200.     assume    ds:code
  201.     clc
  202.     ret
  203.  
  204.  
  205.     public    reset_interface
  206. reset_interface:
  207. ;reset the interface.
  208.     assume    ds:code
  209.     ret
  210.  
  211.  
  212. ;called when we want to determine what to do with a received packet.
  213. ;enter with cx = packet length, es:di -> packet type.
  214.     extrn    recv_find: near
  215.  
  216. ;called after we have copied the packet into the buffer.
  217. ;enter with ds:si ->the packet, cx = length of the packet.
  218.     extrn    recv_copy: near
  219.  
  220.     extrn    count_in_err: near
  221.     extrn    count_out_err: near
  222.  
  223.     public    recv
  224. recv:
  225. ;called from the recv isr.  All registers have been saved, and ds=cs.
  226. ;Upon exit, the interrupt will be acknowledged.
  227.     assume    ds:code
  228. recv_2:
  229.     loadport
  230.     setport    IIR
  231.     in    al,dx            ;any interrupts at all?
  232.     test    al,IIR_IP
  233.     jne    recv_1            ;no.
  234.     and    al,IIR_ID
  235.     cmp    al,IIR_RDA        ;Receiver interrupt
  236.     jne    recv_3
  237.     call    asyrxint
  238.     jmp    recv_2
  239. recv_3:
  240.     cmp    al,IIR_THRE        ;Transmit interrupt
  241.     jne    recv_4
  242.     call    asytxint
  243.     jmp    recv_2
  244. recv_4:
  245. ;process IIR_RLS here.
  246. recv_1:
  247.     ret
  248.  
  249.  
  250. ;Process 8250 receiver interrupts
  251. asyrxint:
  252.  
  253. asyrxint_2:
  254.     loadport
  255.     setport    LSR
  256.     in    al,dx
  257.     test    al,LSR_DR
  258.     je    asyrxint_1
  259.  
  260.     setport    RBR
  261.     in    al,dx
  262. ;Process incoming data;
  263. ; If buffer is full, we have no choice but
  264. ; to drop the character
  265.  
  266.     mov    cx,recv_cnt
  267.     cmp    cx,recv_buf_size
  268.     je    asyrxint_1
  269.  
  270.     push    ds
  271.     pop    es
  272.     mov    di,recv_buf_tail
  273.     stosb
  274.  
  275.     cmp    di,recv_buf_end        ;did we hit the end of the buffer?
  276.     jne    asyrxint_3        ;no.
  277.     mov    di,recv_buf        ;yes - wrap around.
  278. asyrxint_3:
  279.     mov    recv_buf_tail,di
  280.     inc    recv_cnt
  281.  
  282.     cmp    al,FR_END        ;might this be the end of a frame?
  283.     jne    asyrxint_4        ;no.
  284.     call    recv_frame
  285. asyrxint_4:
  286.  
  287.     jmp    asyrxint_2
  288. asyrxint_1:
  289.     ret
  290.  
  291.  
  292. recv_frame:
  293.     mov    si,recv_buf_head    ;process characters.
  294.     mov    bx,recv_cnt
  295.     mov    cx,0            ;count up the size here.
  296. recv_frame_1:
  297.     call    recv_char        ;get a char.
  298.     je    recv_frame_2        ;go if no more chars.
  299.     cmp    al,FR_ESC        ;an escape?
  300.     je    recv_frame_1        ;yes - don't count this char.
  301.     inc    cx            ;no - count this one.
  302.     jmp    recv_frame_1
  303. recv_frame_2:
  304.  
  305.     jcxz    recv_frame_3        ;count zero? yes - just free the frame.
  306. ;we don't need to set the type because none are defined for SLIP.
  307.     push    si            ;save si in case we reject it.
  308.     push    bx
  309.     mov    di,0            ;but we avoid any segment end bullshit.
  310.     call    recv_find        ;look up our type.
  311.     pop    bx
  312.     pop    si
  313.  
  314.     mov    ax,es            ;is this pointer null?
  315.     or    ax,di
  316.     je    recv_frame_3        ;yes - just free the frame.
  317.  
  318.     push    cx
  319.     push    es            ;remember where the buffer pointer is.
  320.     push    di
  321.  
  322.     mov    si,recv_buf_head    ;process characters.
  323.     mov    bx,recv_cnt
  324. recv_frame_4:
  325.     call    recv_char
  326.     je    recv_frame_6        ;yes - we're all done.
  327.     cmp    al,FR_ESC        ;an escape?
  328.     jne    recv_frame_5        ;no - just store it.
  329.  
  330.     call    recv_char        ;get the next character.
  331.     je    recv_frame_6
  332.     cmp    al,T_FR_ESC
  333.     mov    al,FR_ESC        ;assume T_FR_ESC
  334.     je    recv_frame_5        ;yup, that's it - store FR_ESC
  335.     mov    al,FR_END        ;nope, store FR_END
  336. recv_frame_5:
  337.     stosb                ;store the byte.
  338.     jmp    recv_frame_4
  339. recv_frame_6:
  340.     mov    recv_buf_head,si    ;we're skipped to the end.
  341.     mov    recv_cnt,bx
  342.  
  343.     pop    si            ;now give the frame to the client.
  344.     pop    ds
  345.     pop    cx
  346.     assume    ds:nothing
  347.  
  348.     call    recv_copy
  349.     assume    ds:code
  350.     ret
  351.  
  352. recv_frame_3:
  353.     mov    recv_buf_head,si    ;remember the new starting point.
  354.     mov    recv_cnt,bx
  355.     ret
  356.  
  357.  
  358. recv_char:
  359. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  360. ;return with nz, al = next char.  Return zr if there are no more chars in
  361. ;  this frame.
  362.     lodsb
  363.     cmp    si,recv_buf_end
  364.     jb    recv_char_1
  365.     mov    si,recv_buf
  366. recv_char_1:
  367.     dec    bx
  368.     je    recv_char_2
  369.     cmp    al,FR_END
  370. recv_char_2:
  371.     ret
  372.  
  373.  
  374. ;Handle 8250 transmitter interrupts
  375. asytxint:
  376.  
  377.     mov    si,send_buf_head
  378. asytxint_2:
  379.     loadport            ;can we load another character?
  380.     setport    LSR
  381.     in    al,dx
  382.     test    al,LSR_THRE
  383.     je    asytxint_1        ;no.
  384.  
  385.     lodsb                ;fill up the transmit buffer.
  386.     cmp    si,send_buf_end        ;have we hit the end yet?
  387.     jb    asytxint_3        ;no.
  388.     mov    si,send_buf
  389. asytxint_3:
  390.     setport    THR
  391.     out    dx,al
  392.  
  393.     dec    send_cnt        ;keep sending until we run out.
  394.     jne    asytxint_2
  395.  
  396. ;No more characters to transmit -- disable transmit interrupts.
  397.  
  398.     setport    IER            ;Disable transmit interrupts
  399.     mov    ah,IER_TxE
  400.     call    clrbit
  401. ;Call completion interrupt here
  402. asytxint_1:
  403.     mov    send_buf_head,si
  404.     ret
  405.  
  406.  
  407. ;Set bit(s) in I/O port
  408. setbit:
  409. ;enter with dx = port, ah = bit to set.
  410.     in    al,dx
  411.     or    al,ah
  412.     out    dx,al
  413.     ret
  414.  
  415.  
  416. ;Clear bit(s) in I/O port
  417. clrbit:
  418. ;enter with dx = port, ah = bit to set.
  419.     in    al,dx
  420.     not    al            ;perform an and-not using DeMorgan's.
  421.     or    al,ah
  422.     not    al
  423.     out    dx,al
  424.     ret
  425.  
  426.  
  427. ;any code after this will not be kept after initialization.
  428. end_resident    label    byte
  429.  
  430.     public    usage_msg
  431. usage_msg    db    "usage: SLIP8250 packet_int_no [driver_class] [int_no] [io_addr] [baud_rate]",CR,LF,"   [send_buf_size] [recv_buf_size]",CR,LF
  432.         db    "   The driver_class should be SLIP, KISS, AX.25, or a number.",CR,LF,'$'
  433.  
  434.     public    copyright_msg
  435. copyright_msg    db    "Packet driver for SLIP8250, version ",'0'+version,CR,LF
  436.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  437.  
  438. approximate_msg    db    "Warning: This baud rate can only be approximated using the 8250",CR,LF
  439.         db    "because it is not an even divisor of 115200",CR,LF,'$'
  440.  
  441. class_name    db    "Interface class ",'$'
  442. kiss_name    db    "KISS",CR,LF,'$'
  443. ax25_name    db    "AX.25",CR,LF,'$'
  444. slip_name    db    "SLIP",CR,LF,'$'
  445. int_no_name    db    "Interrupt number ",'$'
  446. io_addr_name    db    "I/O port ",'$'
  447. baud_rate_name    db    "Baud rate ",'$'
  448. send_buf_name    db    "Send buffer size ",'$'
  449. recv_buf_name    db    "Receive buffer size ",'$'
  450.  
  451.     extrn    set_recv_isr: near
  452.  
  453. ;enter with si -> argument string, di -> word to store.
  454. ;if there is no number, don't change the number.
  455.     extrn    get_number: near
  456.  
  457. ;enter with si -> argument string.
  458. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  459.     extrn    skip_blanks: near
  460.  
  461.  
  462.     public    parse_args
  463. parse_args:
  464.     call    skip_blanks
  465.     mov    al,[si]            ;now classify the argument.
  466.     or    al,20h            ;convert to lower case (assuming letter).
  467.     cmp    al,'k'
  468.     jne    parse_args_2
  469.     mov    driver_class,10        ;KISS, from packet spec.
  470.     mov    dx,offset kiss_name
  471.     jmp    short parse_args_1
  472. parse_args_2:
  473.     cmp    al,'s'
  474.     jne    parse_args_3
  475.     mov    driver_class,6        ;SLIP, from packet spec.
  476.     mov    dx,offset slip_name
  477.     jmp    short parse_args_1
  478. parse_args_3:
  479.     cmp    al,'a'
  480.     jne    parse_args_4
  481.     mov    driver_class,9        ;AX.25, from packet spec.
  482.     mov    dx,offset ax25_name
  483.     jmp    short parse_args_1
  484. parse_args_4:
  485.     mov    di,offset driver_class
  486.     mov    bx,offset class_name
  487.     call    get_number
  488.     jmp    short parse_args_6
  489. parse_args_1:
  490.     push    dx
  491.     mov    dx,offset class_name
  492.     mov    ah,9
  493.     int    21h
  494.     pop    dx
  495.     mov    ah,9
  496.     int    21h
  497. parse_args_5:
  498.     mov    al,[si]            ;skip to the next blank or CR.
  499.     cmp    al,' '
  500.     je    parse_args_6
  501.     cmp    al,CR
  502.     je    parse_args_6
  503.     inc    si            ;skip the character.
  504.     jmp    parse_args_5
  505. parse_args_6:
  506.     mov    di,offset int_no
  507.     mov    bx,offset int_no_name
  508.     call    get_number
  509.     mov    di,offset io_addr
  510.     mov    bx,offset io_addr_name
  511.     call    get_number
  512.     mov    di,offset baud_rate
  513.     mov    bx,offset baud_rate_name
  514.     call    get_number
  515.     mov    di,offset send_buf_size
  516.     mov    bx,offset send_buf_name
  517.     call    get_number
  518.     mov    di,offset recv_buf_size
  519.     mov    bx,offset recv_buf_name
  520.     call    get_number
  521.     ret
  522.  
  523.  
  524.     public    etopen
  525. etopen:
  526.     pushf
  527.     cli
  528.  
  529.     loadport            ;Purge the receive data buffer
  530.     setport    RBR
  531.     in    al,dx
  532.  
  533.     ;Enable FIFO, set FIFO trigger level to 8
  534.     mov    al,FCR_8
  535.     setport    FCR
  536.     out    dx,al
  537.  
  538.     ;Set line control register: 8 bits, no parity
  539.     mov    al,LCR_8BITS
  540.     setport    LCR
  541.     out    dx,al
  542.  
  543.     ;Turn on receive interrupt enable in 8250, leave transmit
  544.     ; and modem status interrupts turned off for now
  545.     mov    al,IER_DAV
  546.     setport    IER
  547.     out    dx,al
  548.  
  549.     ;Set modem control register: assert DTR, RTS, turn on 8250
  550.     ; master interrupt enable (connected to OUT2)
  551.  
  552.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  553.     setport    MCR
  554.     out    dx,al
  555.  
  556. ;compute the divisor given the baud rate.
  557.     mov    dx,baudclk+2
  558.     mov    ax,baudclk
  559.     mov    bx,0
  560. asy_speed_1:
  561.     inc    bx
  562.     sub    ax,baud_rate
  563.     sbb    dx,baud_rate+2
  564.     jnc    asy_speed_1
  565.     dec    bx
  566.     add    ax,baud_rate
  567.     adc    dx,baud_rate+2
  568.     or    ax,dx
  569.     je    asy_speed_2
  570.  
  571.     mov    dx,offset approximate_msg
  572.     mov    ah,9
  573.     int    21h
  574.  
  575. asy_speed_2:
  576.  
  577.     loadport            ;Purge the receive data buffer
  578.     setport    RBR
  579.     in    al,dx
  580.  
  581.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  582.     setport    LCR
  583.     call    setbit
  584.  
  585.     mov    al,bl            ;Load the two bytes of the divisor.
  586.     setport    DLL
  587.     out    dx,al
  588.     mov    al,bh
  589.     setport    DLM
  590.     out    dx,al
  591.  
  592.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  593.     setport    LCR
  594.     call    clrbit
  595.  
  596.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  597.  
  598. ;set up the various pointers.
  599.     mov    dx,offset end_resident
  600.     mov    send_buf,dx
  601.     mov    send_buf_head,dx
  602.     mov    send_buf_tail,dx
  603.     add    dx,send_buf_size
  604.     mov    send_buf_end,dx
  605.  
  606.     mov    recv_buf,dx
  607.     mov    recv_buf_head,dx
  608.     mov    recv_buf_tail,dx
  609.     add    dx,recv_buf_size
  610.     mov    recv_buf_end,dx
  611.  
  612.     popf
  613.     clc                ;indicate no errors.
  614.     ret
  615.  
  616. code    ends
  617.  
  618.     end
  619.